#pragma once
#include <cstring>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "Log.hpp"
#include "Error.hpp"

const int backlog = 25;

class Sock
{
public:
    Sock()
    {}
    void Socket()  // server client
    {
        _sock = socket(AF_INET,SOCK_STREAM,0);
        // domain：使用本地通信、网络通信（AF_INET）
        // type：哪种协议进行通信，是udp-SOCK_DGRAM,tcp-SOCK_STREAM
        // protocol: 什么协议，默认0即可
        if(_sock < 0)
        {
            logMessage(Fatal,"socket failed...");
            exit(SOCKET_ERR);
        }
    }
    // 未来呢只有服务器才会进行bind，客户端是不需要进行bind的由os自动完成bind的工作

    void Bind(const uint16_t& port) // server
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        // server.sin_addr.s_addr = inet_addr(INADDR_ANY);
        // server.sin_addr.s_addr = ntohl(INADDR_ANY); // 要转化网络序列也不是用inet_addr啊，而是使用ntohl
        server.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_sock,(struct sockaddr*)&server,sizeof(server));
        if(n < 0)
        {
            logMessage(Fatal,"bind failed...");
            exit(BIND_ERR);
        }
    }

    void Listen() // server
    {
        int n = listen(_sock,backlog);
        if(n < 0)
        {
            logMessage(Fatal,"listen falied...");
            exit(LISTEN_ERR);
        }
    }

    int Accept(std::string* clientip, uint16_t* clientport) // server
    {
        struct sockaddr_in client;
        memset(&client,0,sizeof(client));
        socklen_t sz = sizeof(client);

        int sock = accept(_sock,(struct sockaddr*)& client, &sz);
        *clientip = inet_ntoa(client.sin_addr);
        *clientport = ntohs(client.sin_port);

        return sock;
    }
    int Connect(const std::string& serverip,const uint16_t& serverport) // client
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(serverip.c_str());
        server.sin_port = htons(serverport);

        int n = connect(_sock,(struct sockaddr*)&server, sizeof(server));
        return n;
    }

    int Fd()
    {
        return _sock;
    }
    void Close()
    {
        close(_sock);
    }

    ~Sock(){}
private:
    int _sock;
};